/*
 * @author: huangww
 * @Date: 2021-02-26 09:44:09
 * @LastEditTime: 2021-03-01 14:44:35
 * @FilePath: \fmgr\src\core\mgr\ResLoadMgr.ts
 */
namespace core {
  /**
   * 资源类管理设计
   */
  export class ResLoadMgr {
    private static instance: ResLoadMgr;

    private currentLoadItem: ResItem;
    private preloadStack: Array<ResItem>;
    private resLoaded: Array<ResName>;
    private loadType: LOADTYPE;
    private loadState: LOADSTATE;

    constructor() {
      this.preloadStack = [];
      this.resLoaded = [];
      this.loadState = LOADSTATE.NORMAL;
      this.loadType = LOADTYPE.NORMAL;
      RES.addEventListener(RES.ResourceEvent.GROUP_COMPLETE, this.loadComplete, this);
      RES.addEventListener(RES.ResourceEvent.GROUP_LOAD_ERROR, this.loadError, this);
      RES.addEventListener(RES.ResourceEvent.GROUP_PROGRESS, this.progress, this);
      RES.addEventListener(RES.ResourceEvent.ITEM_LOAD_ERROR, this.itemLoadError, this);
    }

    /**
     * 资源组加载,增强资源管理
     * @param names 资源组项名字
     * @param funcComplete 加载完回调函数
     * @param thisObject
     * @param loadingType
     */
    load(names: string | LoadGroup = null, thisObject: Object = null, funcComplete: Function = null, loadingType: LOADTYPE = LOADTYPE.NORMAL) {
      if (!names) {
        funcComplete();
        return;
      }

      let item: LoadGroup;
      if (typeof (names) == "string") {
        item = new LoadGroup([names]);
      } else {
        item = names;
      }
      let loaditem = new ResItem(item);
      loaditem.setLoadCallBack(funcComplete, thisObject);
      loaditem.loadingType = loadingType;
      this.preloadStack.push(loaditem);

      this.checkLoad();
    }

    /**
     * 当前加载项中追加
     */
    loadAppend(names: string | LoadGroup) {
      if (this.loadState == LOADSTATE.LOADING) {
        let item = this.currentLoadItem;
        if (item) {
          let group: LoadGroup = item.loadGroup;
          if (typeof (names) == "string") {
            group.groups.push(names);
          } else {
            group.groups = group.groups.concat(names.groups);
            group.retains = group.retains.concat(names.retains);
            group.count = group.count + names.count;
            item.all = group.count;
          }
        }
      } else {
        this.load(names);
      }
    }

    private checkLoad() {
      if (this.loadState != LOADSTATE.LOADING) {
        let item = this.preloadStack.shift();
        if (item) {
          this.currentLoadItem = item;
          this.startLoad(item);
          return true;
        }
      }
      return false;
    }

    private startLoad(item: ResItem) {
      this.loadState = LOADSTATE.LOADING;
      this.loadType = item.loadingType;
      RES.loadGroup(item.loadGroup.groups[item.current]);

      if (item.loadingType === LOADTYPE.CIRCLE) {
        // Circle.getInstance().show();
      } else if (item.loadingType === LOADTYPE.LOADINGUI) {
        // LoadingUI.getInstance().show(item.current, item.all);
      }
    }

    /**
     * 持有资源不释放
     */
    retainGroup(names: string | Array<string>, retain = true) {
      if (typeof (names) === "string") {
        let resItem = {
          name: names,
          retain: retain
        } as ResName;
        this.addResLoaded(resItem, true);
      } else {
        for (let name of names) {
          let resItem = {
            name: name,
            retain: retain
          } as ResName;
          this.addResLoaded(resItem, true);
        }
      }
    }

    private addResLoaded(item: ResName, overLoad?: boolean) {
      if (overLoad) {
        for (let i of this.resLoaded) {
          if (i.name === item.name) {
            i.retain = item.retain;
          }
          return;
        }
      }
      this.resLoaded.push(item);
    }

    /**
     * 手动释放已加载的被标记资源组
     */
    release() {
      let length = this.resLoaded.length;
      for (let i = length - 1; i >= 0; i--) {
        let item = this.resLoaded[i];
        if (!item.retain) {
          let des = RES.destroyRes(item.name);
          this.resLoaded.splice(i, 1);
        }
      }
    }
    private loadEnd() {
      if (this.loadType === LOADTYPE.CIRCLE) {

      } else if (this.loadType === LOADTYPE.LOADINGUI) {

      }
      this.currentLoadItem = null;
      this.loadType = LOADTYPE.NORMAL;
      this.loadState = LOADSTATE.FINISH;
    }

    private loadComplete(event: RES.ResourceEvent) {
      let item = this.currentLoadItem;
      if (item) {
        item.current++;
        if (item.current < item.all) {
          // console.log("loadComplete", item.current, item.all, item.loadGroup.groups[item.current])
          this.startLoad(item);
          return;
        }

        let loadgroup: LoadGroup = item.loadGroup;
        //解析龙骨
        if (loadgroup.parseList) {
          DBMgr.getInstance().parse(loadgroup.parseList);
        }
        if (item.loadComplete) {
          item.loadComplete.call(item.thisObject, event);
        }
        for (let i of loadgroup.groups) {
          let resItem = {
            name: i,
            retain: loadgroup.isRetain(i)
          } as ResName;
          this.addResLoaded(resItem);
        }
        this.loadEnd();

        this.checkLoad();
      }
    }

    private loadError(event: RES.ResourceEvent) {
      this.loadEnd();
    }

    private progress(event: RES.ResourceEvent) {
      if (this.loadType === LOADTYPE.LOADINGUI) {
        // LoadingUI.getInstance().onProgress(event.itemsLoaded, event.itemsTotal);
      } else if (this.loadType === LOADTYPE.CIRCLE) {

      }
    }

    private itemLoadError(event: RES.ResourceEvent) { }


    static getInstance() {
      if (!this.instance) {
        this.instance = new ResLoadMgr();
      }
      return this.instance;
    }
  }

  class ResItem {
    loadGroup: LoadGroup;
    loadComplete: Function;
    thisObject: Object;
    loadingType: LOADTYPE;
    /**当前项进度 */
    current: number;
    all: number;
    constructor(loadGroup: LoadGroup) {
      this.loadGroup = loadGroup;
      this.current = 0;
      this.all = loadGroup.groups.length;
      this.loadingType = LOADTYPE.NORMAL;
    }
    setLoadCallBack(loadComplete: Function, thisObject) {
      this.loadComplete = loadComplete;
      this.thisObject = thisObject;
    }
  }

  interface ResName {
    name: string;
    retain: boolean;
  }
}